package com.trade.okxserver.util;

import com.google.common.util.concurrent.RateLimiter;
import com.google.gson.Gson;
import com.trade.okxserver.config.OkxProperties;
import com.trade.okxserver.constants.UrlConstants;
import lombok.SneakyThrows;
import okhttp3.Headers;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.ProxyProvider;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

@Component
public class HttpUtils {

    private OkxProperties okxProperties;
    private Gson gson;
    private String baseUrl;
    private volatile AtomicInteger count = new AtomicInteger(0);

    @SneakyThrows
    HttpUtils(WebClient.Builder webClientBuilder, OkxProperties properties) {
        baseUrl = UrlConstants.BASE_URL;
        if (properties.getEnv().equals("aws")) {
            baseUrl = UrlConstants.AWS_BASE_URL;
        } else if (properties.getEnv().equals("demo")) {
            baseUrl = UrlConstants.DEMO_BASE_URL;
        }
        this.okxProperties = properties;
        this.gson = new Gson();
    }

    @SneakyThrows
    public String get(String url, Map<String, Object> params) {
        if (params != null && !params.isEmpty()) {
            url += "?";
            StringBuilder urlBuilder = new StringBuilder(url);
            for (Map.Entry<String, Object> stringObjectEntry : params.entrySet()) {
                urlBuilder.append(stringObjectEntry.getKey()).append("=").append(stringObjectEntry.getValue()).append("&");
            }
            url = urlBuilder.deleteCharAt(urlBuilder.length() - 1).toString();
        }
        OkHttpUtil instance = OkHttpUtil.getInstance();
        return instance.getData(this.baseUrl + url, headersConsumer("GET", url, null), okxProperties.getProxy().getHost(), okxProperties.getProxy().getPort()).body().string();
    }

    @SneakyThrows
    public Mono<String> post(String url, Map<String, String> params) {
        String body = "";
        if (params != null && !params.isEmpty()) {
            body = gson.toJson(params);
        }
        OkHttpUtil instance = OkHttpUtil.getInstance();
        return Mono.just(instance.postData(this.baseUrl + url, params, headersConsumer("POST", url, body), okxProperties.getProxy().getHost(), okxProperties.getProxy().getPort()).body().string());

    }

    @SneakyThrows
    private Headers headersConsumer(String method, String requestPath, String body) {

        int countNum = count.incrementAndGet();
        int size = this.okxProperties.getApiKeyList().size();
        int index = countNum % size;
        OkxProperties.APIKey apiKey = this.okxProperties.getApiKeyList().get(index);
        String timestamp = OKAccessSignGenerator.getISO8601Timestamp();
        String sign = OKAccessSignGenerator.generateOKAccessSign(timestamp, method, requestPath, body, apiKey.getSecretKey());
        HashMap<String, String> params = new HashMap<>();
        params.put("OK-ACCESS-KEY", apiKey.getApiKey());
        params.put("OK-ACCESS-SIGN", sign);
        params.put("OK-ACCESS-TIMESTAMP", timestamp);
        params.put("OK-ACCESS-PASSPHRASE", apiKey.getPassphrase());
        return Headers.of(params);
    }

}
